package customBlockingQueue;

import com.baomidou.mybatisplus.extension.api.R;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayDeque;
import java.util.Deque;
import java.util.concurrent.BlockingDeque;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

@Slf4j
class TestDemo{
    public static void main(String[] args) throws InterruptedException {

        MyBlockingQueue myBlockingQueue = new MyBlockingQueue(3);
        for (int i = 0; i < 10; i++) {
            //添加元素线程
            int finalI = i;
            new Thread(()->{
                try {
                    myBlockingQueue.addElement(new Integer(finalI));
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }


        for (int i = 0; i < 10; i++) {
            //移除元素线程
            new Thread(()->{
                try {
                    log.info("取出元素" + myBlockingQueue.takeElement().toString());;
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }).start();
        }
    }
}


/**
 * 自定义阻塞队列
 */
@Slf4j
public class MyBlockingQueue<T> {

    //定义变量
      //容器
        //队列,先进先出
        private Deque<T> blockingDeque;
      //同步锁
        //ReentrantLock
        private ReentrantLock reentrantLock;
        //标记位,用于唤醒阻塞
          //生产者
          private Condition productCondition;
          //消费者
          private Condition consumerCondition;
      //容量大小
        //size
        private int dequeSize;

      //构造方法
       //初始化数据
    public MyBlockingQueue(int dequeSize) {
        this.blockingDeque = new ArrayDeque<>();
        this.reentrantLock = new ReentrantLock();
        this.productCondition = reentrantLock.newCondition();
        this.consumerCondition = reentrantLock.newCondition();
        this.dequeSize = dequeSize;
    }
    //初始化线程池对象数据
    public MyBlockingQueue(int dequeSize,Runnable runnable) {
        this.blockingDeque = new ArrayDeque<>();
        this.reentrantLock = new ReentrantLock();
        this.productCondition = reentrantLock.newCondition();
        this.consumerCondition = reentrantLock.newCondition();
        this.dequeSize = dequeSize;
    }


    //添加队列元素
    public void addElement(T t) throws InterruptedException {
        //保证线程安全,锁住
        reentrantLock.lock();
        //判断队列是否已满,已满即生产者阻塞等待
        try{
            while((blockingDeque.size() == dequeSize)){
                //满了生产者者阻塞等待
                productCondition.await();
            }
                log.info("添加元素" + t.toString());
                //不满则添加元素
                blockingDeque.addLast(t);
                //唤醒移除队列元素的线程
                consumerCondition.signal();
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            reentrantLock.unlock();
        }
    }


    //移除队列元素
    public T takeElement() throws InterruptedException {
        //保证线程安全,锁住
        reentrantLock.lock();
        try{
            //判断队列是否为空,为空即唤醒添加元素线程
            while (blockingDeque.isEmpty()) {
                //为空则取出线程阻塞等待
                consumerCondition.await();
            }

            T t = blockingDeque.removeFirst();
            //唤醒添加队列元素的线程
            productCondition.signal();
            //不为空则取出元素
            return t;
        }finally {
            reentrantLock.unlock();
        }
    }

}
